package org.bhf.service.view;

/**
 * Copyright (c) 2007, Blue Hole Software. All rights reserved.
 * Code licensed under the Apache 2.0 License:
 * http://www.apache.org/licenses/
 */

import org.bhf.json.JSONWriter;
import org.bhf.service.Constants;
import org.bhf.service.ProcessView;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.lang.reflect.Method;

/**
 * This view processor sets the status to 500 and returns a JSON object
 * {"name":&lt;exception name&gt;,"message":&lt;exception_message&gt;}
 */
public class JSONExceptionProcessView implements ProcessView
{
    private final Throwable exception;
    private final int       status;

    /**
     * Render the view as a JSON exception. The status will be 404.
     *
     * @param service Service object
     * @param method The target service method
     * @param exception Must not be <code>null</code>
     */
    public JSONExceptionProcessView( final Object service, final Method method, final Throwable exception )
    {
        this.exception  = exception;
        this.status     = HttpURLConnection.HTTP_INTERNAL_ERROR;
    }

    /**
     * Render the view as a JSON exception. The status will be 404.
     *
     * @param exception Must not be <code>null</code>
     */
    public JSONExceptionProcessView( final Throwable exception )
    {
        this( null, null, exception );
    }

    /**
     * Render the view as a JSON exception with the given status code.
     *
     * @param exception Must not be <code>null</code>
     * @param status HTTP status code
     */
    public JSONExceptionProcessView( final Throwable exception, final int status )
    {
        this.exception  = exception;
        this.status     = status;
    }

    /**
     *
     * @param request Servlet request
     * @param response Servlet response
     * @param servletContext The servlet context for this application
     * @throws java.io.IOException ConversionError writing body
     * @exclude
     */
    public void processView( final HttpServletRequest request, final HttpServletResponse response, final ServletContext servletContext )
        throws IOException
    {
        if( response.isCommitted() )
            return;

        final StringBuffer json = new StringBuffer( getJSON() );
        final String callback = request.getParameter( Constants.ERROR_CALLBACK_PARAMETER );

        if( callback == null )
            response.setStatus( status );

        response.setContentType( "text/javascript" );

        if( callback != null )
        {
            json.insert( 0, callback + "(" );
            json.append( ")" );
        }

        response.setContentLength( json.length() );
        final PrintWriter out = response.getWriter();
        out.print( json.toString() );
        out.close();
    }

    private String  exceptionName()
    {
        final String className = exception.getClass().getName();
        final int i = className.lastIndexOf('.');
        return className.substring( i + 1 );
    }

    private String  getJSON()
        throws IOException
    {
        return new JSONWriter().writeObject( new ExceptionDescription( exceptionName(), exception.getMessage() ) );
    }

    /**
     * @exclude
     */
    public static class ExceptionDescription
    {
        private String name;
        private String message;

        public ExceptionDescription( String name, String message )
        {
            this.name       = name;
            this.message    = message;
        }

        public String getName()
        {
            return name;
        }

        public String getMessage()
        {
            return message;
        }
    }
}